<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="referrer" content="no-referrer" />
    <title>生成3dtiles的json文件</title>
    <style>
        body {
            position: absolute;
            margin: 0;
            width: 100%;
            height: 100%;
        }

        #mapContainer {
            left: 0px;
            top: 0px;
            width: 100%;
            height: 100%;
            float: left;
        }
    </style>
</head>

<body>
    <!-- <canvas id="canvasTest" width="400" height="400"></canvas> -->
    <div id="mapContainer" style="position: relative;">
    </div>

</body>
<script src=""></script>
<script src='/GiswayEngine.js'></script>

<script src='threeMin.js'></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/three@0.162.0/build/three.min.js"></script> -->
<script type="text/javascript">

    let modelUrlArray;
    let ThreeDboxArray = []; //用于存储3dtiles需要用到的包围盒
    let boxArray = []; //里面的元素是：{box: newBox, modelArray: newModelArray}
    let urlBoxMap = new Map();
    let datumPoint = [122.00151626214978, 40.71106690828059, 10.2]; //数据的基准点，这里使用经纬度
    let dataUrl = 'http://localhost:3000/modelData/3dtiles/'; //'http://localhost:3000/gltfData/3dtiles/';
    let gltfUpAxis = 'Z'; //'Y' or 'Z'
    let boxScale = 0.95; //包围盒的缩放比例
    let geometricError = 10;
    var rootJson = {
        "asset":
        {
            "gltfUpAxis": 'Z', //渲染的时候Z轴是向上的，所以这里设置为Z；即便是Y轴向上，也会在OverLay中做旋转
            "modelUpAxis": gltfUpAxis, //定义模型的朝向，Y轴向上还是Z轴向上。在加载3dtiles的时候，会根据这个值来判断是否需要旋转模型
            "version": "1.0",
        },
        "root": {
            "boundingVolume": { box: [] }, //"box", "sphere"
            "children": [],
            "geometricError": geometricError,
            "transform": []
        }
    };

    window.app = new GE.App('mapContainer', {
        position: [datumPoint[0], datumPoint[1], 1000],
        lookAt: [datumPoint[0], datumPoint[1], 0],
        cameraScrollSpeed: 15,
        minZoom: 3,
        maxZoom: 22,
        ambientLightIntensity: 5,
        ambientLightType: 'hemiSphere',
        useCarpet: true,
        background: "Fog",
        useDefaultTexture: true, //是否使用瓦片默认纹理
        baseLayer: [
            {
                url: ' https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
                readableUrl: true,
                tileType: 'image',
            },
        ]
    });

    getModelPathArray(); //从服务器端获取要处理模型的路径数组

    function generate3dtiles(url) {
        // if(url != 'model/JFKJ0313_SM_JinFkj_67.fbx'){
        //     return;
        // }
        let type = url.substring(url.lastIndexOf(".") + 1);
        let model = new GE.OverLay({
            type: type, //
            // url: 'http://localhost:9000/examples/resources/fbx/xqazm.fbx',
            // url: 'http://localhost:9000/examples/resources/fbx/FBX/5.FBX',
            // url:'http://192.168.2.43:9000/examples/resources/fbx/box.gltf',
            url: dataUrl + url,
            gltfUpAxis: gltfUpAxis, //Z轴朝上
            position: [datumPoint[0], datumPoint[1], datumPoint[2]],
            // changeEmissive: true,
            isComputeBoxFor3dtile: true, //计算3dtiles数据需要的包围盒
            // scale: [100, 100, 100],
            // rotation: [45, 0, 0],
            success: function (overlay) {
                let boundingMsg = computeBoundingVolume(overlay.children[0]);
                let boundingBox = boundingMsg.box;
               
                urlBoxMap.set(url, boundingMsg.boundingVolume);
                boxArray.push({ box: boundingBox, modelArray: [url] });

                if (boxArray.length == modelUrlArray.length) {
                    const rootBox = new THREE.Box3();

                    // 遍历所有包围盒并将它们合并，得到整个根节点最大的包围盒
                    ThreeDboxArray.forEach((box) => {
                        rootBox.union(box);
                    });
                    // let totalArea = getArea(rootBox);
                    // console.log(mergedBox);

                    let boundingVolume = getBoundingVolumeBox(rootBox);
                    rootJson.root.boundingVolume.box = boundingVolume;
                    // mergedresultJson.root.transform = [
                    //     1, 0, 0, 0,
                    //     0, 1, 0, 0,
                    //     0, 0, 1, 0,
                    //     -2175287.3894734886, 4468232.746726356, 3984551.6487376457, 1 //椭球坐标系
                    // ];

                    let webMercator = GE.GeoUtils.P84toWeb(datumPoint[0], datumPoint[1]);
                    rootJson.root.transform = [
                        1, 0, 0, 0,
                        0, 1, 0, 0,
                        0, 0, 1, 0,
                        webMercator.x, webMercator.y, datumPoint[2], 1  //web墨卡托坐标系
                    ];

                    // console.log(JSON.stringify(mergedresultJson));
                    // console.log(mergedresultJson);
                    boxArray = mergeBox(boxArray, boxScale); //每个盒子扩大，然后把相交的盒子做合并
                    let fileIndex = 0;
                    boxArray.forEach(element => { //{box, modelArray}
                        //包围盒要重新再计算，转换成3dtiles需要的box。然后再生成3dtiles需要的json对象
                        element.box = getBoundingVolumeBox(element.box);

                        let chiledJsonContent = {
                            asset: rootJson.asset,
                            root: {
                                "boundingVolume": { box: element.box }, //"box"
                                "children": [],
                                "geometricError": geometricError
                            }
                        };
                        element.modelArray.forEach(url => {
                            let childJsonInSub = {
                                boundingVolume: { box: urlBoxMap.get(url) },
                                // content: { uri: url },
                                content: { uri: '../' + url },
                                geometricError: geometricError
                            };

                            chiledJsonContent.root.children.push(childJsonInSub);
                        });
                        // console.log(JSON.stringify(chiledJsonContent));
                        sendDataToServe('child', JSON.stringify(chiledJsonContent), '/sub/' + fileIndex + '.json');

                        let childJsonInRoot = {
                            boundingVolume: { box: element.box },
                            content: { uri: './sub/' + fileIndex + '.json' },
                            geometricError: geometricError
                        };
                        rootJson.root.children.push(childJsonInRoot); //向根节点json对象中添加子节点
                        fileIndex++;
                    });
                    // console.log(boxArray);
                    let rootJsonStr = JSON.stringify(rootJson);
                    // console.log(rootJsonStr);
                    // console.log('----------------------');
                    sendDataToServe('root', rootJsonStr, '/root.json');
                }
                
                // setTimeout(() => {
                //     app.remove(model);
                // }, 500);
            }
        })
        app.add(model);
    }

    function getArea(box){
        // 获取包围盒的最小点和最大点
        var min = box.min;
        var max = box.max;

        // 计算x和y方向上的尺寸
        var width = max.x - min.x;  // x方向尺寸
        var height = max.y - min.y; // y方向尺寸

        // 计算x和y平面的面积
        var area = width * height;
        return area;
    }

    function sendDataToServe(key, data, filePath) {
        console.log(filePath);
        
        fetch('http://localhost:3000/submit', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ key: key, value: data, filePath: filePath }), // 发送的数据
        })
            .then(response => response.text())
            .then(result => console.log(result))
            .catch(error => console.error('Error:', error));
    }

    function getModelPathArray() {
        fetch('http://localhost:3000/')
            .then((response) => {
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                return response.json();
            })
            .then((data) => {
                console.log(data);
                modelUrlArray = data;

                modelUrlArray.forEach(element => {
                    generate3dtiles(element);
                });
            })
            .catch((error) => {
                console.error('There was a problem with the fetch operation:', error);
            });
    }

    function computeBoundingVolume(object) { //把模型的包围盒计算出来，为生成3dtiles数据做准备
        // 获取Group的包围盒
        let box = new THREE.Box3();
        // box = box.expandByObject(object); // 通过Group扩展Box3
        object.updateMatrixWorld(true); // 确保世界矩阵是最新的
        box = box.setFromObject(object, true); // 通过Group扩展Box3

        // if(object.rotation.x != 0){
        //     let rotateMatrix = new THREE.Matrix4();
        //     rotateMatrix.makeRotationX(Math.PI / 2);
        //     box.applyMatrix4(rotateMatrix);
        // }
        // console.log(box);
        let boundingVolume = getBoundingVolumeBox(box);
        ThreeDboxArray.push(box);

        return { boundingVolume: boundingVolume, box: box };
        
    }

    function getBoundingVolumeBox(box) {
        const center = new THREE.Vector3();
        box.getCenter(center);

        let xHalf = box.max.x - center.x;
        let yHalf = box.max.y - center.y;
        let zHalf = box.max.z - center.z;

        let boundingVolumeBox = [
            center.x, center.y, center.z,
            xHalf, 0, 0,
            0, yHalf, 0,
            0, 0, zHalf
        ];
        return boundingVolumeBox;
    }

    function sacleBox(box, scale) { //把box扩大scale倍
        let sizeVector = new THREE.Vector3();
        sizeVector = box.getSize(sizeVector);
        let size = sizeVector.length() * (scale - 1);
        box.expandByScalar(size);
        return box;
    }

    function mergeBox(boxArray, boxScale) {
        let isRun = true;
        while (isRun) {
            let isMergeBox = false; //是否发生了box合并
            breakLabel:
            for (let i = 0; i < boxArray.length; i++) {
                let curElement = boxArray[i];
                let cloneCurBox = sacleBox(curElement.box.clone(), boxScale); //把curElement中的box扩大boxScale倍
                for (let j = 0; j < boxArray.length; j++) {
                    if (i == j) {
                        continue;
                    }

                    let otherElement = boxArray[j];
                    let cloneOtherBox = sacleBox(otherElement.box.clone(), boxScale);//把otherElement中的box扩大boxScale倍
                    if (cloneCurBox.intersectsBox(cloneOtherBox)) { //两个box相交
                        isMergeBox = true;

                        let newBox = curElement.box.union(otherElement.box);
                        //删除boxArray中的curElement和otherElement, 并且创建一个新的元素: {newBox, curElement.modelArray和otherElement.modelArray合并 }, 把这个新元素插入到boxArray中
                        let newModelArray = curElement.modelArray.concat(otherElement.modelArray);
                        let newElement = { box: newBox, modelArray: newModelArray };
                        let newBoxArray = [];
                        for (let i = 0; i < boxArray.length; i++) {
                            let element = boxArray[i];
                            if (element == curElement) {
                                continue;
                            }
                            if (element == otherElement) {
                                continue;
                            }
                            newBoxArray.push(element);
                        }
                        newBoxArray.push(newElement);
                        boxArray = newBoxArray;
                        break breakLabel;
                    }
                }
            }
            isRun = isMergeBox;
        }
        return boxArray;
    }

</script>

</html>